package com.sundablog.spring.framework.context;

import com.sundablog.spring.framework.annotation.SDAutowired;
import com.sundablog.spring.framework.annotation.SDController;
import com.sundablog.spring.framework.annotation.SDService;
import com.sundablog.spring.framework.beans.SDBeanWrapper;
import com.sundablog.spring.framework.beans.config.SDBeanDefinition;
import com.sundablog.spring.framework.beans.support.SDBeanDefinitionReader;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Title:
 * @Package com.sundablog.spring.framework.context
 * @Description: TODO
 * @author: 孙达
 * @date: 2020/04/16 11:48
 * @Copyright: All rights Reserved, Designed By www.sundablog.com
 */
public class SDApplicationContext {


    private SDBeanDefinitionReader reader;

    private Map<String, SDBeanDefinition> beanDefinitionMap = new HashMap<String, SDBeanDefinition>();

    private Map<String,SDBeanWrapper> factoryBeanInstanceCache = new HashMap<String, SDBeanWrapper>();

    private Map<String,Object> factoryBeanObjectCache = new HashMap<String, Object>();

    public SDApplicationContext(String... configLocations) {
        try {
            //1、加载配置文件
            reader = new SDBeanDefinitionReader(configLocations);
            //2、解析配置文件，封装beanDefinition
            List<SDBeanDefinition> beanDefinitions = reader.loadBeanDefinitions();
            //3、把beanDefinition缓存起来
            //beanDefinitionMap
            doRegistBeanDefinition(beanDefinitions);
            doAutowrited();
        } catch (Exception e){
            e.printStackTrace();
        }




    }

    private void doAutowrited() {
        //调用getBean

        for (Map.Entry<String, SDBeanDefinition> beanDefinitionEntry : this.beanDefinitionMap.entrySet()) {
            String beanName = beanDefinitionEntry.getKey();
            //调用getBean方法
            getBean(beanName);
        }

    }

    private void doRegistBeanDefinition(List<SDBeanDefinition> beanDefinitions) throws Exception {
        for (SDBeanDefinition beanDefinition : beanDefinitions) {
            if(this.beanDefinitionMap.containsKey(beanDefinition.getFactoryBeanName())){
                throw new Exception("The " + beanDefinition.getFactoryBeanName() + "is exists");
            }
            beanDefinitionMap.put(beanDefinition.getFactoryBeanName(),beanDefinition);
            beanDefinitionMap.put(beanDefinition.getBeanClassName(),beanDefinition);
        }

    }

    //Bean的实例化，DI是从这个方法开始的
    public Object getBean(String beanName){
        //1、拿到配置信息
        SDBeanDefinition beanDefinition = this.beanDefinitionMap.get(beanName);
        //2、返射实例化
        Object instance = instantiateBean(beanName,beanDefinition);
        //3、封装成BeanWrapper
        SDBeanWrapper beanWrapper = new SDBeanWrapper(instance);
        //4、保存到IoC容器
        factoryBeanInstanceCache.put(beanName,beanWrapper);
        //5、执行依赖注入
        populateBean(beanName,beanDefinition,beanWrapper);
        return beanWrapper.getWrapperInstance();
    }

    private void populateBean(String beanName, SDBeanDefinition beanDefinition, SDBeanWrapper beanWrapper) {


        Object instance = beanWrapper.getWrapperInstance();
        Class<?> clazz = beanWrapper.getWrapperClass();
        //判断注解
        if (!clazz.isAnnotationPresent(SDController.class) || clazz.isAnnotationPresent(SDService.class)){
            return;
        }

        //遍历循环所有声明的字段
        for (Field field : clazz.getDeclaredFields()) {

            //判断是否加了SDAutowired注解
            if (!field.isAnnotationPresent(SDAutowired.class)){
                return;
            }

            SDAutowired autowired = field.getAnnotation(SDAutowired.class);
            //判断以后没有自定义beanName，就默认根据类型
            String autowiredBeanName = autowired.value().trim();
            if ("".equals(autowiredBeanName)){
                autowiredBeanName = field.getType().getName();
            }
            //暴力访问
            field.setAccessible(true);
            try {
                if (this.factoryBeanInstanceCache.get(autowiredBeanName) == null){
                    return;
                }
                //注入的对象应该从容器里面那
                field.set(instance,this.factoryBeanInstanceCache.get(autowiredBeanName).getWrapperInstance());
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                continue;
            }


        }

    }


    /**
     * 创建真正的实力对象
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object instantiateBean(String beanName, SDBeanDefinition beanDefinition) {
        String className = beanDefinition.getBeanClassName();
        Object instance = null;
        try {

            if (this.factoryBeanObjectCache.containsKey(beanName)){
                instance =this.factoryBeanObjectCache.get(beanName);
            } else {
                Class<?> clazz = Class.forName(className);
                //2、默认的类名首字母小写
                instance = clazz.newInstance();
                this.factoryBeanObjectCache.put(beanName,instance);
            }


        } catch (Exception e){
            e.printStackTrace();
        }
        return instance;
    }

    public Object getBean(Class beanClass){
        return getBean(beanClass.getName());
    }

    public int getBeanDefinitionCount() {
        return  this.beanDefinitionMap.size();
    }


    public String[] getBeanDefinitionNames() {
        return this.beanDefinitionMap.keySet().toArray(new String[this.beanDefinitionMap.size()]);
    }
}
